package com.icesoft.mock.builder;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import com.icesoft.mock.base.IMockListener;

import lombok.Getter;

public class MockBuilder {
	@Getter
	Map<String, String> params = new HashMap<>();
	@Getter
	Map<String, String> headers = new HashMap<>();
	@Getter
	MockHttpSession session;
	@Getter
	String url;
	@Getter
	String content;
	MockHttpServletRequestBuilder builder;
	@Getter
	MediaType mediaType = MediaType.APPLICATION_FORM_URLENCODED;
	@Getter
	IMockListener mockListener;

	public MockBuilder mockListener(IMockListener mockListener) {
		this.mockListener = mockListener;
		return this;
	}

	public static MockBuilder httpGet(String url) {
		url = resolverUrl(url);
		return new MockBuilder(url, MockMvcRequestBuilders.get(url));
	}

	public static MockBuilder httpPost(String url) {
		url = resolverUrl(url);
		return new MockBuilder(url, MockMvcRequestBuilders.post(url));
	}

	static String resolverUrl(String url) {
		if (!url.startsWith("/")) {
			url = "/" + url;
		}
		return url;
	}

	MockBuilder(String url, MockHttpServletRequestBuilder builder) {
		this.url = url;
		this.builder = builder;
		headers.put("x-requested-with", "XMLHttpRequest");
	}

	public MockBuilder content(String content) {
		if (mediaType == MediaType.APPLICATION_FORM_URLENCODED) {
			this.mediaType = MediaType.APPLICATION_JSON_UTF8;
		}
		this.content = content;
		return this;
	}

	public MockBuilder mediaType(MediaType mediaType) {
		this.mediaType = mediaType;
		return this;
	}

	public MockBuilder mockSession(MockHttpSession session) {
		this.session = session;
		return this;
	}

	public MockBuilder mockSession(String name, Object value) {
		if (this.session == null) {
			this.session = new MockHttpSession();
			this.session.putValue(name, value);
		}
		return this;
	}

	public MockBuilder param(String name, String value) {
		params.put(name, value);
		return this;
	}

	public MockBuilder header(String name, String value) {
		headers.put(name, value);
		return this;
	}

	public MockBuilder addHeaders(Map<String, String> map) {
		map.forEach((key, value) -> {
			headers.putIfAbsent(key, value);
		});
		return this;
	}

	public MockBuilder addParams(Map<String, String> map) {
		map.forEach((key, value) -> {
			params.putIfAbsent(key, value);
		});
		return this;
	}

	public MockHttpServletRequestBuilder build() {
		builder.contentType(mediaType);
		for (Map.Entry<String, String> entry : headers.entrySet()) {
			builder.header(entry.getKey(), entry.getValue());
		}
		for (Map.Entry<String, String> entry : params.entrySet()) {
			builder.param(entry.getKey(), entry.getValue());
		}
		if (content != null) {
			builder.content(content);
		}
		return builder;
	}

}
